package crypto;

import java.math.BigInteger;
import java.util.Map;

import org.bouncycastle.math.ec.ECPoint;

import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;

/**
 * SM2密钥对Bean
 * 
 * @author Potato
 *
 */
public class SM2KeyPair {

	private final ECPoint publicKey;
	private final BigInteger privateKey;

	public SM2KeyPair(ECPoint publicKey, BigInteger privateKey) {
		this.publicKey = publicKey;
		this.privateKey = privateKey;
	}

	public ECPoint getPublicKey() {
		return publicKey;
	}

	public String getPublicKeyStr() {
		return bytesToStr(publicKey.getEncoded(false));
	}

	public BigInteger getPrivateKey() {
		return privateKey;
	}

	public String toJson() {
		String ret = "{\"publicKey\":\"";
		ret += bytesToStr(publicKey.getEncoded(false));
		ret += "\",\"privateKey\":\"";
		ret += privateKey.toString(16);
		ret += "\"}";
		return ret;
	}

	public String pub2Json() {
		String ret = bytesToStr(publicKey.getEncoded(false));
		return ret;
	}

	public static SM2KeyPair fromJson(String jsonStr) {
		Map<String, String> jo = new Gson().fromJson(jsonStr, new TypeToken<Map<String, String>>() {
		}.getType());
		String publicKeyStr = jo.get("publicKey");
		String privateKeyStr = jo.get("privateKey");
		ECPoint point = SM2.importPublicKey(str2Byte(publicKeyStr));
		return new SM2KeyPair(point, new BigInteger(privateKeyStr, 16));
	}

	public static ECPoint publickeyStr2ECPoint(String pubKey) {
		ECPoint point = SM2.importPublicKey(str2Byte(pubKey));
		return point;
	}

	private static byte[] str2Byte(String str) {
		byte[] ret = new byte[str.length() / 2];
		for (int i = 0; i < str.length() / 2; i++) {
			int val = (char2Int(str.charAt(i * 2)) << 4) + (char2Int(str.charAt(i * 2 + 1)));
			ret[i] = (byte) (val & 0xff);
		}
		return ret;
	}

	private static int char2Int(char c) {
		int ret = c;
		if (c >= 'a' && c <= 'f') {
			ret = '0' + 10 + c - 'a';
		}
		ret = ret - '0';
		if (ret >= 0 && ret < 16) {
			return ret;
		} else
			throw new IllegalArgumentException("the input should be 0-9 and a-f, but received " + c);
	}

	private String bytesToStr(byte[] bytes) {
		StringBuilder sb = new StringBuilder();
		for (byte b : bytes) {
			sb.append(byte2Char((b >> 4) & 0xf));
			sb.append(byte2Char(b & 0xf));
		}
		return sb.toString();
	}

	private char byte2Char(int i) {
		if (i < 10)
			return (char) (i + '0');
		else
			return (char) (i - 10 + 'a');
	}
}
